# -*- coding: utf-8 -*-

import numpy as np
np.random.seed(1337) # for reproducibility
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation,Convolution2D,MaxPooling2D, Flatten, SimpleRNN
from tensorflow.keras.optimizers import RMSprop,Adam

time_steps = 28 # same as the height of the image
input_size = 28 # same as the width of the image
batch_size = 50 # num of image to train each time
batch_index = 0 
output_size = 10 # num of result
cell_size = 50 # hidden unit
learning_rate = 0.001


# download the mnist to the path '~/.keras/dattasets/' if it is the first time to be called
# X shape (60,000 28x28), y shape (60,000,)
(X_train, y_train), (X_test, y_test) = mnist.load_data()

print('X_train.shape=',X_train.shape) # X_train.shape= (60000, 28, 28)
print('y_train.shape=',y_train.shape) # y_train.shape= (60000,)


# data pre-processing
X_train = X_train.reshape(-1,28,28) / 255 # normalize
X_test = X_test.reshape(-1,28,28) / 255 # normalize
y_train = np_utils.to_categorical(y_train, num_classes = 10)
y_test = np_utils.to_categorical(y_test, num_classes = 10)

print('X_train.shape=',X_train.shape) # X_train.shape= (60000, 1, 28, 28)
print('y_train.shape=',y_train.shape) # y_train.shape= (60000, 10)

# build RNN model
model = Sequential()

# RNN cell
model.add(SimpleRNN(
        units = cell_size, # output_dim
        batch_input_shape = (None,time_steps,input_size)
))

# output layer
model.add(Dense(output_size))
model.add(Activation('softmax'))

# Anther way to define your optimizer
adam = Adam(learning_rate = 1e-4)

# We add metrics to get more results you want to see
model.compile(
        optimizer = adam,
        loss='categorical_crossentropy',
        metrics=['accuracy']
    )

print('Training ----------')
for step in range(4001):
    # data shape = (batch_num, steps, inputs/outputs)
    X_batch = X_train[batch_index: batch_size + batch_index, :, :]
    Y_batch = y_train[batch_index: batch_size + batch_index, :]
    cost = model.train_on_batch(X_batch, Y_batch)

    batch_index += batch_size
    batch_index = 0 if batch_index >= X_train.shape[0] else batch_index
    
    if step % 500 == 0:
        loss, accuracy = model.evaluate(X_test, y_test, batch_size = y_test.shape[0], verbose=False)
        print('test cost: ', cost, 'test accuracy: ', accuracy)
    
